package com.onecar.carplatform.common.protocol.annotations;

import com.onecar.carplatform.common.constants.Jt808MsgId;
import com.onecar.carplatform.common.protocol.basics.JtMessage;

import java.io.File;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;

/**
 * @Author : ljq
 * @Description : 解析注解工具类
 * @Date : 2021/8/19 11:44
 * @Version : 1.0
 */
public class JtMsgClassUtil {
    /**
     * @Author ljq
     * @Description 获取指定包下的 JtMessage 类原型
     * @Date 11:46 2021/8/19
     * @Param [java.lang.String]
     * @Return java.util.HashMap<java.lang.Integer, java.lang.Class < com.onecar.carplatform.common.protocol.basics.JtMessage>>
     **/
    public static HashMap<Integer, Class<? extends JtMessage>> getClass(String packagePath) {
        HashMap<Integer, Class<? extends JtMessage>> jtMsgClassMap = new HashMap<>();

        String dirPath = packagePath.replace('.', '/');
        try {
            Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(dirPath);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                if ("file".equals(protocol)) {
                    String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8);
                    addClass(jtMsgClassMap, filePath, packagePath);
                }
            }
        } catch (Exception e) {
            System.out.println("parse dir " + dirPath + " to get class failed");
        }

        return jtMsgClassMap;
    }

    private static void addClass(HashMap<Integer, Class<? extends JtMessage>> classes, String filePath, String packageName) throws Exception {
        File[] files = new File(filePath).listFiles(file -> (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory());
        ClassLoader classLoader = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                return super.loadClass(name);
            }
        };

        assert files != null;
        for (File file : files) {
            String fileName = file.getName();
            if (file.isFile()) {
                String className = fileName.substring(0, fileName.lastIndexOf("."));
                if (!packageName.isEmpty()) {
                    className = packageName + "." + className;
                }
                Class<?> aClass = classLoader.loadClass(className);
                addJtMsgClass(classes, aClass);
            }
        }
    }

    private static void addJtMsgClass(HashMap<Integer, Class<? extends JtMessage>> classes, Class<?> aClass) {
        if (!JtMessage.class.isAssignableFrom(aClass))
            return;

        JtMsgDesc msgDesc = aClass.getDeclaredAnnotation(JtMsgDesc.class);
        if (msgDesc == null || msgDesc.msgId() == Jt808MsgId.INVALID_ID)
            return;

        Class<? extends JtMessage> jtMsgSubClass = aClass.asSubclass(JtMessage.class);
        classes.put(msgDesc.msgId().getMsgId(), jtMsgSubClass);
    }
}
